using Kiwi.Container.Caching;
using Kiwi.Container.DependencyInjection;
using Kiwi.Container.Lifetime;
using Kiwi.Container.Registration;
using Kiwi.Container.Scope;
using Kiwi.Container.TransientSupport;

namespace Kiwi.Container
{
    public static class ComponentRegistrationExtensions
    {
        public static IComponentRegistration<T> WithTag<T>(this IComponentRegistration<T> registration, object tag)
        {
            registration.Tag = tag;
            return registration;
        }

        public static IComponentRegistration WithTag(this IComponentRegistration registration, object tag)
        {
            registration.Tag = tag;
            return registration;
        }

        public static IComponentRegistration<T> NoLifetime<T>(this IComponentRegistration<T> registration)
        {
            registration.LifetimeManager = NullLifetimeManager.Default;
            return registration;
        }

        public static IComponentRegistration NoLifetime(this IComponentRegistration registration)
        {
            registration.LifetimeManager = NullLifetimeManager.Default;
            return registration;
        }

        public static IComponentRegistration<T> WithLifetime<T>(this IComponentRegistration<T> registration)
        {
            registration.LifetimeManager = LifetimeManager.Default;
            return registration;
        }

        public static IComponentRegistration WithLifetime(this IComponentRegistration registration)
        {
            registration.LifetimeManager = LifetimeManager.Default;
            return registration;
        }

        private static IComponentRegistration<T> SetScope<T>(this IComponentRegistration<T> registration,
                                                             IComponentCacheResolver cacheResolver,
                                                             IComponentScope scope)
        {
            registration.CacheResolver = cacheResolver;
            registration.ComponentScope = scope;
            return registration;
        }

        private static IComponentRegistration SetScope(this IComponentRegistration registration,
                                                       IComponentCacheResolver cacheResolver,
                                                       IComponentScope scope)
        {
            registration.CacheResolver = cacheResolver;
            registration.ComponentScope = scope;
            return registration;
        }

        public static IComponentRegistration<T> Global<T>(this IComponentRegistration<T> registration)
        {
            return registration.PerScope(ComponentScope.Global);
        }

        public static IComponentRegistration Global(this IComponentRegistration registration)
        {
            return registration.PerScope(ComponentScope.Global);
        }

        public static IComponentRegistration<T> Transient<T>(this IComponentRegistration<T> registration)
        {
            return registration.SetScope(TransientComponentCacheResolver.Default, TransientComponentScope.Default);
        }

        public static IComponentRegistration Transient(this IComponentRegistration registration)
        {
            return registration.SetScope(TransientComponentCacheResolver.Default, TransientComponentScope.Default);
        }

        public static IComponentRegistration<T> Local<T>(this IComponentRegistration<T> registration)
        {
            return registration.PerScope(ComponentScope.Local);
        }

        public static IComponentRegistration Local(this IComponentRegistration registration)
        {
            return registration.PerScope(ComponentScope.Local);
        }

        public static IComponentRegistration<T> PerHttpRequest<T>(this IComponentRegistration<T> registration)
        {
            return registration.PerScope(ComponentScope.HttpRequest);
        }

        public static IComponentRegistration PerHttpRequest(this IComponentRegistration registration)
        {
            return registration.PerScope(ComponentScope.HttpRequest);
        }

        public static IComponentRegistration<T> PerHttpSession<T>(this IComponentRegistration<T> registration)
        {
            return registration.PerScope(ComponentScope.HttpSession);
        }

        public static IComponentRegistration PerHttpSession(this IComponentRegistration registration)
        {
            return registration.PerScope(ComponentScope.HttpSession);
        }

        public static IComponentRegistration<T> PerScope<T>(this IComponentRegistration<T> registration,
                                                            IComponentScope scope)
        {
            return registration.SetScope(ComponentCacheResolver.Default, scope);
        }

        public static IComponentRegistration PerScope(this IComponentRegistration registration, IComponentScope scope)
        {
            return registration.SetScope(ComponentCacheResolver.Default, scope);
        }

        public static IComponentRegistration<T> As<T>(this IComponentRegistration registration)
        {
            return new ComponentRegistrationAs<T>(registration);
        }

        public static IComponentRegistration<T> InjectNone<T>(this IComponentRegistration<T> registration)
        {
            registration.InjectProperties = Properties.None;
            return registration;
        }

        public static IComponentRegistration InjectNone(this IComponentRegistration registration)
        {
            registration.InjectProperties = Properties.None;
            return registration;
        }

        public static IComponentRegistration<T> InjectAll<T>(this IComponentRegistration<T> registration)
        {
            registration.InjectProperties = Properties.All;
            return registration;
        }

        public static IComponentRegistration InjectAll(this IComponentRegistration registration)
        {
            registration.InjectProperties = Properties.All;
            return registration;
        }

        public static IComponentRegistration<T> InjectUnset<T>(this IComponentRegistration<T> registration)
        {
            registration.InjectProperties = Properties.Unset;
            return registration;
        }

        public static IComponentRegistration InjectUnset(this IComponentRegistration registration)
        {
            registration.InjectProperties = Properties.Unset;
            return registration;
        }
    }
}